//-------------------------------------------------------------------
//	Copyright (c) 2012-2014 Zhirnov Andrey
//	This file is part of the "UXGEN-ES" project.
//	See copyright notice in "Engine.h".
//-------------------------------------------------------------------

#include "Graphics/Resources/Sprite2D.h"
#include "Graphics/Systems/GraphicsEngine.h"

namespace Engine
{
namespace Graphics
{
	
/*
=================================================
	constructor
=================================================
*/
	Sprite2D::Sprite2D (const EngineSubSystemsRef ess) :
		Resource( EResource::SPRITE_2D, ess ), _texture( ess ), _color(0xFF)
	{
	}

/*
=================================================
	destructor
=================================================
*/
	Sprite2D::~Sprite2D ()
	{
	}
	
/*
=================================================
	Draw
=================================================
*/
	void Sprite2D::Draw (const rect &region, const Instance &inst) const
	{
		Animation const &	anim = _animations[ inst._animIndex ].second;

		BatchRenderPtr	br = ESS()->GetGraphicsEngine()->GetBatchRender();

		if ( anim.blend )
		{
			color4u		prev_color = _color;	prev_color.A() = uint8( prev_color.A() * inst._frameInterpolation );
			color4u		next_color = _color;	next_color.A() = uint8( next_color.A() * (1.0f - inst._frameInterpolation) );

			br->AddBatch( _material, Primitives::Rect2D( region, _texcoords[ inst._nextFrame ], next_color ) );
			br->AddBatch( _material, Primitives::Rect2D( region, _texcoords[ inst._prevFrame ], prev_color ) );
		}
		else
		{
			br->AddBatch( _material, Primitives::Rect2D( region, _texcoords[ inst._frameInterpolation > 0.5f ?
							inst._nextFrame : inst._prevFrame ], _color ) );
		}
	}
	
/*
=================================================
	Update
=================================================
*/
	void Sprite2D::Update (Instance &inst, float timeDelta) const
	{
		Animation const &	anim	= _animations[ inst._animIndex ].second;
		uint const			count	= anim.FramesCount();

		inst._frameTime	+= timeDelta;

		float const	frame		= inst._frameTime / anim.rate;
		float const	prev_frame	= Floor( frame );
		float const	next_frame	= Ceil( frame );

		inst._nextFrame			 = _frames[ uint( next_frame ) % count + anim.frameInterval[0] ];
		inst._prevFrame			 = _frames[ uint( prev_frame ) % count + anim.frameInterval[0] ];
		inst._frameInterpolation = (frame - prev_frame) / (next_frame - prev_frame);

		if ( inst._frameTime > anim.rate * count )
		{
			if ( not inst._looping )
			{
				inst._nextFrame			 = anim.frameInterval[1];
				inst._frameTime			 = 0.0f;
				inst._frameInterpolation = 1.0f;
			}

			inst.OnAnimationEnd( (Sprite2D *)this );
		}
	}
	
/*
=================================================
	SetAnimation
=================================================
*/
	bool Sprite2D::SetAnimation (Instance &inst, uint animType, float time) const
	{
		inst._animType	= uvec2( animType );
		inst._frameTime	= time;
		inst._animIndex	= -1;

		return _animations.FindIndex( inst._animType, inst._animIndex );
	}
	
/*
=================================================
	ChangeAnimation
=================================================
*/
	bool Sprite2D::ChangeAnimation (Instance &inst, uint animType) const
	{
		inst._animType[1] = animType;
		inst._frameTime	 = 0.0f;
		inst._animIndex	 = -1;

		return _animations.FindIndex( inst._animType, inst._animIndex );
	}
	
/*
=================================================
	HasAnimation
=================================================
*/
	bool Sprite2D::HasAnimation (uint animType) const
	{
		return HasAnimation( animType, animType );
	}
	
/*
=================================================
	HasAnimation
=================================================
*/
	bool Sprite2D::HasAnimation (uint animBegin, uint animEnd) const
	{
		usize	idx = -1;
		return _animations.FindIndex( uvec2( animBegin, animEnd ), idx );
	}
	
/*
=================================================
	SwapData
=================================================
*/
	bool Sprite2D::SwapData (const ResourcePtr &res)
	{
		CHECK_ERR( Resource::SwapData( res ) );

		Sprite2D *	spr = res.ToPtr< Sprite2D >();

		this->_texture.SwapData( &spr->_texture );
		this->_texcoords.SwapMem( spr->_texcoords );
		this->_frames.SwapMem( spr->_frames );
		this->_animations.SwapMem( spr->_animations );
		this->_material.SwapMem( spr->_material );

		return true;
	}
		
/*
=================================================
	IsLoadedWithParams
=================================================
*/
	bool Sprite2D::IsLoadedWithParams (const ResLoadParams &params) const
	{
		return Resource::IsLoadedWithParams( params );
	}
	
/*
=================================================
	IsValid
=================================================
*/
	bool Sprite2D::IsValid () const
	{
		return	_texture.IsValid() and _material.IsValid() and
				not _animations.Empty() and not _frames.Empty();
	}

/*
=================================================
	New
=================================================
*/
	Sprite2DPtr  Sprite2D::New (const EngineSubSystemsRef ess)
	{
		return BaseObject::_New( new Sprite2D( ess ) );
	}
	
/*
=================================================
	GetDefaultLoadParams
=================================================
*/
	Sprite2D::SpriteLoadParams  Sprite2D::GetDefaultLoadParams ()
	{
		return SpriteLoadParams();
	}


}	// Graphics
}	// Engine